/**
 * @file global_definitions.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2020-10-29
 * 
 * @copyright Copyright (c) 2020
 * 
 */
#pragma once
//====================================================================
//  preprocessor macros
//====================================================================
#define Emax 5
#define FILELINE \
    (string() + __FILE__ + ":" + to_string(__LINE__))
// Loop simplification
#define LOOP_1D(i, imin, imax) for (size_t i = imin; i < imax; ++i)
#define LOOP_2D(i, imin, imax, j, jmin, jmax) \
    for (size_t i = imin; i < imax; ++i)      \
        for (size_t j = jmin; j < jmax; ++j)
#define LOOP_3D(i, imin, imax, j, jmin, jmax, k, kmin, kmax) \
    for (size_t i = imin; i < imax; ++i)                     \
        for (size_t j = jmin; j < jmax; ++j)                 \
            for (size_t k = kmin; k < kmax; ++k)
//macro for calculation
#define FOR_INNER_CELLS                                  \
    LOOP_3D(i, index_cell_.at(kXm), index_cell_.at(kXp), \
            j, index_cell_.at(kYm), index_cell_.at(kYp), \
            k, index_cell_.at(kZm), index_cell_.at(kZp))
#define FOR_ALL_CELLS                   \
    LOOP_3D(i, 0, block_mesh_res.at(X), \
            j, 0, block_mesh_res.at(Y), \
            k, 0, block_mesh_res.at(Z))

#define FOR_INNER_FACES_X                                \
    LOOP_3D(i, index_face_.at(kXm), index_face_.at(kXp), \
            j, index_cell_.at(kYm), index_cell_.at(kYp), \
            k, index_cell_.at(kZm), index_cell_.at(kZp))
#define FOR_INNER_FACES_Y                                \
    LOOP_3D(i, index_cell_.at(kXm), index_cell_.at(kXp), \
            j, index_face_.at(kYm), index_face_.at(kYp), \
            k, index_cell_.at(kZm), index_cell_.at(kZp))
#define FOR_INNER_FACES_Z                                \
    LOOP_3D(i, index_cell_.at(kXm), index_cell_.at(kXp), \
            j, index_cell_.at(kYm), index_cell_.at(kYp), \
            k, index_face_.at(kZm), index_face_.at(kZp))
#define FOR_ALL_FACES FOR_ALL_CELLS // they are the same thing

#define FOR_BOUNDARY_CELLS_XM                                    \
    LOOP_3D(i, index_boundary_.at(kXm), index_cell_.at(kXm),     \
            j, index_boundary_.at(kYm), index_boundary_.at(kYp), \
            k, index_boundary_.at(kZm), index_boundary_.at(kZp))
#define FOR_BOUNDARY_CELLS_XP                                    \
    LOOP_3D(i, index_cell_.at(kXp), index_boundary_.at(kXp),     \
            j, index_boundary_.at(kYm), index_boundary_.at(kYp), \
            k, index_boundary_.at(kZm), index_boundary_.at(kZp))
#define FOR_BOUNDARY_CELLS_YM                                    \
    LOOP_3D(i, index_boundary_.at(kXm), index_boundary_.at(kXp), \
            j, index_boundary_.at(kYm), index_cell_.at(kYm),     \
            k, index_boundary_.at(kZm), index_boundary_.at(kZp))
#define FOR_BOUNDARY_CELLS_YP                                    \
    LOOP_3D(i, index_boundary_.at(kXm), index_boundary_.at(kXp), \
            j, index_cell_.at(kYp), index_boundary_.at(kYp),     \
            k, index_boundary_.at(kZm), index_boundary_.at(kZp))
#define FOR_BOUNDARY_CELLS_ZM                                    \
    LOOP_3D(i, index_boundary_.at(kXm), index_boundary_.at(kXp), \
            j, index_boundary_.at(kYm), index_boundary_.at(kYp), \
            k, index_boundary_.at(kZm), index_cell_.at(kZm))
#define FOR_BOUNDARY_CELLS_ZP                                    \
    LOOP_3D(i, index_boundary_.at(kXm), index_boundary_.at(kXp), \
            j, index_boundary_.at(kYm), index_boundary_.at(kYp), \
            k, index_cell_.at(kZp), index_boundary_.at(kZp))

#define FOR_GHOST_CELLS_XM                               \
    LOOP_3D(i, 0, kNumGhostX,                            \
            j, index_cell_.at(kYm), index_cell_.at(kYp), \
            k, index_cell_.at(kZm), index_cell_.at(kZp))
#define FOR_GHOST_CELLS_XP                                \
    LOOP_3D(i, index_cell_.at(kXp), block_mesh_res.at(X), \
            j, index_cell_.at(kYm), index_cell_.at(kYp),  \
            k, index_cell_.at(kZm), index_cell_.at(kZp))
#define FOR_GHOST_CELLS_YM                              \
    LOOP_3D(i, index_cell_.at(kXm), index_cell_.at(kXp), \
            j, 0, kNumGhostY,                           \
            k, index_cell_.at(kZm), index_cell_.at(kZp))
#define FOR_GHOST_CELLS_YP                               \
    LOOP_3D(i, index_cell_.at(kXm), index_cell_.at(kXp),  \
            j, index_cell_.at(kYp), block_mesh_res.at(Y), \
            k, index_cell_.at(kZm), index_cell_.at(kZp))
#define FOR_GHOST_CELLS_ZM                               \
    LOOP_3D(i, index_cell_.at(kXm), index_cell_.at(kXp), \
            j, index_cell_.at(kYm), index_cell_.at(kYp), \
            k, 0, kNumGhostZ)
#define FOR_GHOST_CELLS_ZP                               \
    LOOP_3D(i, index_cell_.at(kXm), index_cell_.at(kXp), \
            j, index_cell_.at(kYm), index_cell_.at(kYp), \
            k, index_cell_.at(kZp), block_mesh_res.at(Z))

//=================================================================================================
//								Pre-claimer
//=================================================================================================
class Cell;
class LevelSetCell;
class BaseBlock;
class FluidNode;
class BaseSolver;
class FluidSolver;
class BaseCSPInitializer;
class CSPShockBubble2D;
//=================================================================================================
//								class pointer
//=================================================================================================
typedef Cell *p_Cell;
typedef LevelSetCell *p_LSCell;
//=================================================================================================
//								enum_declarations
//=================================================================================================
//All kinds of Boundary Conditions
enum BConditions
{
    Interior,
    Inflow,
    Outflow,
    Symmetry,
    Periodic,
    Wall,
    UDF_xm,
    UDF_xp,
    UDF_ym,
    UDF_yp,
    UDF_zm,
    UDF_zp
};
//all kinds of solvers
enum SolverType
{
    kCompressibleSinglePhase,
    kCompressibleMultiPhase,
    kIncompressibleSinglePhase,
    kIncompressibleMultiPhase,
    kPureLeveSet,
};
enum ConservativeVariables
{
    MASS,
    MX,
    MY,
    MZ,
    ENERGY
};
enum PrimitiveVariables
{
    DEN,
    VX,
    VY,
    VZ,
    PRESSURE
};
enum CSPCase /*compressible single phase cases*/
{
    kShockBubble2D,
};
enum PLSCase /*pure level-set cases*/
{
    kCircleAdvection2D,
    kZalesakDisk2D,
    kCircleVortex2D,
    kCircleVortex3D
};
enum Directions
{
    X,
    Y,
    Z
};
enum Locations
{
    kXm, //x-
    kXp, //x+
    kYm, //y-
    kYp, //y+
    kZm, //z-
    kZp  //z+
};